/**
给定整数数组 nums 和整数 k，请返回数组中第 k 个最大的元素。

请注意，你需要找的是数组排序后的第 k 个最大的元素，而不是第 k 个不同的元素。

示例 1：
输入：nums = [3,2,1,5,6,4], k = 2
输出：5

示例 2：
输入：nums = [3,2,3,1,2,4,5,5,6], k = 4
输出：4

提示：

1 <= k <= nums.length <= 10^4
-10^4 <= nums[i] <= 10^4

*/

#pragma once

#include <algorithm>
#include <cstdlib>
#include <ctime>
#include <vector>

using namespace std;

class Solution {
   public:
    int quickSelect(vector<int>& a, int l, int r, int index) {
        int q = randomPartition(a, l, r);
        if (q == index) {
            return a[q];
        } else {
            return q < index ? quickSelect(a, q + 1, r, index)
                             : quickSelect(a, l, q - 1, index);
        }
    }

    inline int randomPartition(vector<int>& a, int l, int r) {
        int i = rand() % (r - l + 1) + l;
        swap(a[i], a[r]);
        return partition(a, l, r);
    }

    inline int partition(vector<int>& a, int l, int r) {
        int x = a[r], i = l - 1;
        for (int j = l; j < r; ++j) {
            if (a[j] <= x) {
                swap(a[++i], a[j]);
            }
        }
        swap(a[i + 1], a[r]);
        return i + 1;
    }

    int official_findKthLargest(vector<int>& nums, int k) {
        srand(time(0));
        return quickSelect(nums, 0, nums.size() - 1, nums.size() - k);
    }

    int findKthLargest(vector<int>& nums, int k) {
        // 由于元素在很小的范围内，可以直接使用桶排序
        int bucket[20001] = {0};
        for (const auto& n : nums) {
            bucket[n + 10000] += 1;
        }
        auto i = 20000;
        for (; i >= 0; i--) {
            if (bucket[i] > 0) {
                k -= bucket[i];
                if (k <= 0) {
                    break;
                }
            }
        }
        return i - 10000;
    }
};

int answer(vector<int> nums, int k) {
    auto a = Solution();
    return a.findKthLargest(nums, k);
}

int official_answer(vector<int> nums, int k) {
    auto a = Solution();
    return a.official_findKthLargest(nums, k);
}